package net.lab1024.sa.base.common.elk;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Component
@Aspect
public class ELKLogAspect {

    private static final Logger elkLogger = LoggerFactory.getLogger("ELK_LOGGER");

    @Autowired
    private ObjectMapper objectMapper;

    @Around("@annotation(logToELK)")
    public Object logToELK(ProceedingJoinPoint joinPoint, LogToELK logToELK) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        Exception exception = null;

        try {
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            long executionTime = System.currentTimeMillis() - startTime;
            logToELK(joinPoint, logToELK, result, exception, executionTime);
        }
    }

    private void logToELK(ProceedingJoinPoint joinPoint, LogToELK logToELK,
                          Object result, Exception exception, long executionTime) {
        try {
            Map<String, Object> logData = new HashMap<>();

            // 基本信息
            logData.put("timestamp", Instant.now());
            logData.put("level", exception != null ? "ERROR" : logToELK.level());
            logData.put("annotationValue", logToELK.value());

            // 方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            logData.put("className", signature.getDeclaringTypeName());
            logData.put("methodName", signature.getName());
            logData.put("message", "测试信息");
            //生成100000 到 200000 之间的随机数
            int randomNum = (int) (Math.random() * 100000 + 100000);
            logData.put("appid", randomNum);

            // 参数信息
            logData.put("args", getArgsJson(joinPoint.getArgs(), signature.getParameterNames()));

            // 执行结果
            if (exception != null) {
                logData.put("exception", exception.getMessage());
                logData.put("stackTrace", getStackTrace(exception));
            } else {
                logData.put("result", objectMapper.writeValueAsString(result));
            }

            logData.put("executionTime", executionTime);
            logData.put("thread", Thread.currentThread().getName());

            // 使用专门的ELK Logger输出
            if ("ERROR".equals(logData.get("level"))) {
                elkLogger.error(objectMapper.writeValueAsString(logData));
            } else {
                elkLogger.info(objectMapper.writeValueAsString(logData));
            }

        } catch (Exception e) {
            // 避免ELK日志记录本身抛出异常影响业务
            System.err.println("Failed to log to ELK: " + e.getMessage());
        }
    }

    private String getArgsJson(Object[] args, String[] paramNames) {
        try {
            Map<String, Object> argsMap = new HashMap<>();
            for (int i = 0; i < args.length; i++) {
                // 敏感参数过滤
                if (paramNames[i].toLowerCase().contains("password")
                        || paramNames[i].toLowerCase().contains("token")) {
                    argsMap.put(paramNames[i], "***");
                } else {
                    argsMap.put(paramNames[i], args[i]);
                }
            }
            return objectMapper.writeValueAsString(argsMap);
        } catch (Exception e) {
            return "{}";
        }
    }

    private String getStackTrace(Exception e) {
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw));
        return sw.toString();
    }
}